using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using CustomCMS.API;
using CustomCMS.API.Persistance;
using CustomCMS.API.ObjectModel;
using CustomCMS.API.Util;
using System.IO;
using log4net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

public partial class _Default : CustomCMSBasePage
{
    private static readonly ILog _log = LogManager.GetLogger(typeof(_Default));
    private IPersistanceProvider _provider = null;

    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            string action = GetMandatoryRequestParameter("action");
			string userId = GetMandatoryRequestParameter("userId");
            string clientVersion = GetMandatoryRequestParameter("version");
            string serverVersion = CustomCMS.API.Util.ConfigurationHandler.Version;

            _provider = CMSServer.GetProvider();


            if (clientVersion != serverVersion)
                throw new Exception(string.Format("Client version ({0}) is not compatible with server version ({1}).\nPlease clear page cache, and retry.", clientVersion, serverVersion));

			if (!_provider.IsActionAllowed(action, userId)) 
                throw new Exception("User '"+userId+"' is not allowed to perform '"+action+"'.");

            switch (action)
            {
				case "do_login":
					DoLogin();
					break;
				case "create_repository":
                    CreateRepository();
                    break;
				case "get_template":
					GetTemplate();
					break;
				case "set_template":
                    SetTemplate();
                    break;
				case "get_page":
					GetPage();
					break;
				case "set_page":
					SetPage();
					break;
                case "lock_template":
                case "lock_page":
                    LockElement();
                    break;
                case "unlock_template":
                case "unlock_page":
                    UnlockElement();
                    break;
                case "package_repository":
                    PackageRepository();
                    break;
                case "create_directory":
					CreateDirectory();
					break;
				case "generate_page":
					GeneratePage();
					break;
                case "generate_repository":
                    GenerateRepository();
                    break;
                case "generate_status":
                    GenerateRepositoryStatus();
                    break;
                case "generate_repository_kill":
                    KillGeneration();
                    break;
                case "get_tree":
                    GetTree();
                    break;
                case "delete_template":
                case "delete_page":
                    DeleteElement();
					break;
                case "delete_template_directory":
                case "delete_page_directory":
                    DeleteDirectory();
					break;
                case "move_template":
                case "move_page":
                    MoveElement();
                    break;
                case "set_section_states":
                    SetSectionStates();
                    break;
				default:
                    throw new Exception("unknown request: "+action);
            }

        }
        catch (Exception ex)
        {
            Response.Write(CreateResponse(ex.Message, ResponseStatus.Fail));
            _log.Error(ex.ToString());
        }
    }

    private void SetSectionStates()
    {
        string userId = GetMandatoryRequestParameter("userId");
        string pageId = GetMandatoryRequestParameter("pageId");
        string location = GetMandatoryRequestParameter("path");
        string states = GetMandatoryRequestParameter("states");

        _provider.SetSectionStates(userId, pageId, location, states);

        Response.Write(CreateResponse("section states set successfully", ResponseStatus.Success));
    }

    private void CreateRepository()
    {
        _provider.CreateRepository();
		Response.Write(CreateResponse("repository created successfully", ResponseStatus.Success));
    }

	private void DoLogin()
	{
		string userId = GetMandatoryRequestParameter("userId");
		string password = GetMandatoryRequestParameter("password");
		_provider.Authenticate(userId, password);

		ConfigurationHandler config = (ConfigurationHandler)ConfigurationManager.GetSection("CustomCMS");
		XmlNode packaging = config.Packaging.Clone();
		XmlNodeList nodes = packaging.SelectNodes("//option[@users and not(contains(concat(',',@users,','),'," + userId + ",'))]");
		foreach (XmlNode node in nodes) node.ParentNode.RemoveChild(node);
		nodes = packaging.SelectNodes("select[not(option)]");
		if (!_provider.IsActionAllowed("package_repository", userId) || nodes.Count > 0) packaging.RemoveAll();

		Response.Write(CreateResponse(packaging.ChildNodes.Count > 0? packaging.OuterXml : "", ResponseStatus.Success));
	}

	private void GetTemplate()
	{
		string templateId = GetMandatoryRequestParameter("templateId");
		string location = GetMandatoryRequestParameter("path");
		string userId = GetMandatoryRequestParameter("userId");

		Template template = _provider.GetTemplate(templateId, location);
        string versions = _provider.GetVersions(templateId, location, ElementType.template);

        Response.Write(CreateResponse("<root><![CDATA[" + template.Content + "]]></root>" + versions, ResponseStatus.Success));
	}
    
	private void SetTemplate()
    {
        string templateId = GetMandatoryRequestParameter("templateId");
        string location = GetMandatoryRequestParameter("path");
        string userId = GetMandatoryRequestParameter("userId");
		string content = string.IsNullOrEmpty(Request["content"]) ? "" : Request["content"];
		string comment = string.IsNullOrEmpty(Request["comment"]) ? "" : Request["comment"];
		string title = string.IsNullOrEmpty(Request["title"]) ? "" : Request["title"];

        _provider.SetTemplate(templateId, location, userId, content, comment, title);

		Response.Write(CreateResponse("template set successfully", ResponseStatus.Success));
    }

	private void GetPage()
	{
		string pageId = GetMandatoryRequestParameter("pageId");
		string path = GetMandatoryRequestParameter("path");
		string userId = GetMandatoryRequestParameter("userId");

        List<string> missing;
		CustomCMS.API.ObjectModel.Page page = _provider.GetPage(pageId, path, out missing);
        string missingTemplates = missing.Count == 0 ? "" : "<missing>" + string.Join("", missing.ConvertAll<string>(delegate(string t) { return "<template>" + t + "</template>"; }).ToArray()) + "</missing>";
        string versions = _provider.GetVersions(pageId, path, ElementType.page);

        Response.Write(CreateResponse(page.Content + missingTemplates + versions, ResponseStatus.Success));
	}

	private void LockElement()
	{
		string type = GetMandatoryRequestParameter("type");
		string path = GetMandatoryRequestParameter("path");
		string userId = GetMandatoryRequestParameter("userId");
		string elementId = GetMandatoryRequestParameter("elementId");

		_provider.Lock((ElementType)Enum.Parse(typeof(ElementType), type), elementId, path, userId);

		Response.Write(CreateResponse("Element locked successfully", ResponseStatus.Success));
	}

	private void UnlockElement()
	{
		string type = GetMandatoryRequestParameter("type");
		string path = GetMandatoryRequestParameter("path");
		string userId = GetMandatoryRequestParameter("userId");
		string elementId = GetMandatoryRequestParameter("elementId");

		_provider.Unlock((ElementType)Enum.Parse(typeof(ElementType), type), elementId, path, userId);

		Response.Write(CreateResponse("Element unlocked successfully", ResponseStatus.Success));
	}

	private void SetPage()
	{
		string pageId = GetMandatoryRequestParameter("pageId");
		string location = GetMandatoryRequestParameter("path");
		string userId = GetMandatoryRequestParameter("userId");
		string content = string.IsNullOrEmpty(Request["content"]) ? "" : Request["content"];
		string comment = string.IsNullOrEmpty(Request["comment"]) ? "" : Request["comment"];
		string title = string.IsNullOrEmpty(Request["title"]) ? "" : Request["title"];
		string templateId = GetMandatoryRequestParameter("templateId");
        string sectionStates = GetMandatoryRequestParameter("states");

        _provider.SetPage(pageId, location, userId, title, comment, content, templateId, sectionStates);

		Response.Write(CreateResponse("page set successfully", ResponseStatus.Success));
	}

	private void DeleteElement()
	{
		string type = GetMandatoryRequestParameter("type");
		string path = GetMandatoryRequestParameter("path");
		string userId = GetMandatoryRequestParameter("userId");
		string elementId = GetMandatoryRequestParameter("elementId");

		_provider.Delete((ElementType)Enum.Parse(typeof(ElementType), type),elementId, path,userId);

		Response.Write(CreateResponse("Element deleted successfully", ResponseStatus.Success));
	}

    private void DeleteDirectory()
    {
        string type = GetMandatoryRequestParameter("type");
        string path = GetMandatoryRequestParameter("path");
        string userId = GetMandatoryRequestParameter("userId");

        _provider.DeleteDirectory((ElementType)Enum.Parse(typeof(ElementType), type), path, userId);

        Response.Write(CreateResponse("directory deleted successfully", ResponseStatus.Success));
    }

    private void MoveElement()
    {
        string type = GetMandatoryRequestParameter("type");
        string path = GetMandatoryRequestParameter("path");
        string userId = GetMandatoryRequestParameter("userId");
        string elementId = GetMandatoryRequestParameter("elementId");
        string to = GetMandatoryRequestParameter("to");

        _provider.MoveElement((ElementType)Enum.Parse(typeof(ElementType), type), elementId, path, to, userId);

        Response.Write(CreateResponse("item moved successfully", ResponseStatus.Success));
    }

    private void PackageRepository()
    {
		ConfigurationHandler config = (ConfigurationHandler)ConfigurationManager.GetSection("CustomCMS");

        string wwwPath = System.IO.Path.Combine(config.Repository,@"root\www");

		string lang = GetMandatoryRequestParameter("LanguageName");

        string exportPath = System.IO.Path.Combine(config.ExportPath,lang + "." + config.ExportDomain);

		string script = GetMandatoryRequestParameter("packagingTool");
        bool isScript = script.ToLower().EndsWith(".js");
        System.Diagnostics.Process proc = new System.Diagnostics.Process();
        proc.EnableRaisingEvents = false;
        proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(script);
        proc.StartInfo.FileName = isScript ? "CScript" : Path.GetFileName(script);
        proc.StartInfo.Arguments = (isScript ? "\"" + script + "\" " : "") + lang + " \"" + wwwPath + "\" \"" + exportPath + "\"";
        try
        {
            proc.Start();
            if (!proc.WaitForExit(60000)) throw new Exception("Packaging process timed out");
        }
        catch (Exception e)
        {
            throw new Exception("Having a problem executing the following packaging script: " + script + "\n" + e.Message);
        }

		File.Delete(config.TargetZipFilename.Replace("$1", exportPath));
        CustomCMS.API.Util.ZipFolder.ZipFiles(exportPath, exportPath);
        
        Response.Write(CreateResponse("repository packaged successfully", ResponseStatus.Success));
    }

    private void CreateDirectory()
	{
		string type = GetMandatoryRequestParameter("type");
		string path = GetMandatoryRequestParameter("path");

		_provider.CreateDirectory((ElementType)Enum.Parse(typeof(ElementType), type), path);

		Response.Write(CreateResponse("directory created successfully", ResponseStatus.Success));
	}

	private void GeneratePage()
	{
		string pageId = GetMandatoryRequestParameter("pageId");
		string directoryId = GetMandatoryRequestParameter("path");

		string warnings = _provider.GeneratePage(pageId, directoryId);

        if (warnings == null || warnings.Length == 0) Response.Write(CreateResponse("page generated successfully", ResponseStatus.Success));
        else Response.Write(CreateResponse("page generation issued the following warnings:\n"+warnings, ResponseStatus.Fail));
	}

	private void GenerateRepository()
	{
        string userId = GetMandatoryRequestParameter("userId");

        string warnings = _provider.GenerateRepository(userId, _provider.IsActionAllowed("generate_repository_kill", userId));

        if (warnings == null || warnings.Length == 0) Response.Write(CreateResponse("repository generated successfully", ResponseStatus.Success));
        else Response.Write(CreateResponse("repository generation issued the following warnings:\n"+warnings, ResponseStatus.Fail));
	}

    private void GenerateRepositoryStatus()
    {
        string status = _provider.GenerateRepositoryStatus();
        Response.Write(CreateResponse(status, status == null? ResponseStatus.Fail : ResponseStatus.Success));
    }

    private void KillGeneration()
    {
        _provider.KillGenerationLock();
        Response.Write(CreateResponse("Portal generation terminated.", ResponseStatus.Success));
    }

    private void GetTree()
    {
        StringBuilder tree = new StringBuilder(_provider.GetTemplatesTree());
        tree.Append(_provider.GetPagesTree());

        Response.Write(CreateResponse(tree.ToString(), ResponseStatus.Success));
    }
/*
	private void GetTemplateTree()
	{
		string tree = _provider.GetTemplatesTree();

		Response.Write(CreateResponse(tree, ResponseStatus.Success));
	}

	private void GetPageTree()
	{
		string tree = _provider.GetPagesTree();

		Response.Write(CreateResponse(tree, ResponseStatus.Success));
	}
*/
}
